#include "SpotLightComponent.h"
#include "SceneSystem.h"
#include <math.h>

IEngineComponentRegistry spotLightComponentRegistery("SpotLightComponent", SpotLightComponent::Deserialize);

SpotLightComponent::SpotLightComponent()
{
	this->position = D3DXVECTOR3(0,0,0);
	this->color = D3DXVECTOR3(1,1,1);
	this->radius = 1;
	this->angle = (float)D3DX_PI;
	this->decayExponent = 0;
	this->lookAt = D3DXVECTOR3(1,1,1);
}

SpotLightComponent::SpotLightComponent(D3DXVECTOR3 position, D3DXVECTOR3 color, float radius, float angle, float decayExponent, D3DXVECTOR3 lookAt)
{
	this->position = position;
	this->color = color;
	this->radius = radius;
	this->angle = angle;
	this->decayExponent = decayExponent;
	this->lookAt = lookAt;
}

SpotLightComponent::~SpotLightComponent(void)
{
}

D3DXVECTOR3 SpotLightComponent::getPosition()
{
	return position;
}

void SpotLightComponent::setPosition(D3DXVECTOR3 position)
{
	this->position = position;
}

D3DXVECTOR3 SpotLightComponent::getColor()
{
	return color;
}

void SpotLightComponent::setColor(D3DXVECTOR3 color)
{
	this->color = color;
}

float SpotLightComponent::getRadius()
{
	return radius;
}

void SpotLightComponent::setRadius(float radius)
{
	this->radius = radius;
}

float SpotLightComponent::getAngle()
{
	return angle;
}

void SpotLightComponent::setAngle(float angle)
{
	this->angle = angle;
}

float SpotLightComponent::getDecayExponent()
{
	return decayExponent;
}

void SpotLightComponent::setDecayExponent(float decayExponent)
{
	this->decayExponent = decayExponent;
}

D3DXVECTOR3 SpotLightComponent::getLookAt()
{
	return lookAt;
}

void SpotLightComponent::setLookAt(D3DXVECTOR3 lookAt)
{
	this->lookAt = lookAt;
}

D3DXMATRIX SpotLightComponent::getWorld()
{
	D3DXVECTOR3 lookAtNorm;
	D3DXVec3Normalize(&lookAtNorm,& lookAt);
	D3DXVECTOR3 rotateAxis;
	float rotateAngle;

	if (lookAtNorm == D3DXVECTOR3(0,1,0))
	{
		rotateAxis = D3DXVECTOR3(1,0,0);
		rotateAngle = (float)D3DX_PI;
	}
	else
	{
		D3DXVECTOR3 pv1 = D3DXVECTOR3(0, -1, 0);
		D3DXVec3Cross(&rotateAxis, &pv1, &lookAtNorm);
		rotateAngle = acos(D3DXVec3Dot(&pv1,& lookAtNorm));
	}
	float xzScale = tan(angle / 2) * radius;

	D3DXMATRIX mScale;
	D3DXMATRIX mRotate;
	D3DXMATRIX mPosition;
	D3DXMatrixScaling(&mScale, xzScale, radius, xzScale);
	D3DXMatrixRotationAxis(&mRotate,& rotateAxis, rotateAngle);
	D3DXMatrixTranslation(&mPosition, position.x, position.y, position.z);
	
	return mScale * mRotate * mPosition;
}

float SpotLightComponent::getAngleCosine()
{
	return cos(angle/2);
}

D3DXVECTOR3 SpotLightComponent::getNormalLookAt()
{
	D3DXVECTOR3 lookAtNorm;
	D3DXVec3Normalize(&lookAtNorm,& lookAt);
	return lookAtNorm;
}

void SpotLightComponent::Serialize(EnginePointer<ISerializerWriteContext>& context, char* name)
{
	context->StartItem(name, "SpotLightComponent", "1.0");
	context->SerializeProperty("componentId", this->componentId);
	context->SerializeProperty("radius", radius);
	context->SerializeProperty("angle", angle);
	context->SerializeProperty("decayExponent", decayExponent);
	context->SerializeProperty("positionX", position.x);
	context->SerializeProperty("positionY", position.y);
	context->SerializeProperty("positionZ", position.z);
	context->SerializeProperty("colorR", color.x);
	context->SerializeProperty("colorG", color.y);
	context->SerializeProperty("colorB", color.z);
	context->SerializeProperty("lookAtX", lookAt.x);
	context->SerializeProperty("lookAtY", lookAt.y);
	context->SerializeProperty("lookAtZ", lookAt.z);
	context->EndItem(name);
}

IEngineComponent* SpotLightComponent::Deserialize(EnginePointer<ISerializerReadContext>& context)
{
	SpotLightComponent* spotLight = new SpotLightComponent();
	int index = 0;
	char* childName = context->ChildName(index);

	while (childName != NULL)
	{
		if (strcmp(childName, "componentId") == 0)
		{
			spotLight->componentId = context->ChildValueAsULongLong(index);
		}
		else if (strcmp(childName, "radius") == 0)
		{
			float radius = context->ChildValueAsFloat(index);
			spotLight->setRadius(radius);
		}
		else if (strcmp(childName, "angle") == 0)
		{
			float angle = context->ChildValueAsFloat(index);
			spotLight->setAngle(angle);
		}
		else if(strcmp(childName, "decayExponent") == 0)
		{
			float decayExponent = context->ChildValueAsFloat(index);
			spotLight->setDecayExponent(decayExponent);
		}
		else if(strcmp(childName, "positionX") == 0)
		{
			D3DXVECTOR3 position = spotLight->getPosition();
			position.x = context->ChildValueAsFloat(index);
			spotLight->setPosition(position);
		}
		else if(strcmp(childName, "positionY") == 0)
		{
			D3DXVECTOR3 position = spotLight->getPosition();
			position.y = context->ChildValueAsFloat(index);
			spotLight->setPosition(position);
		}
		else if(strcmp(childName, "positionZ") == 0)
		{
			D3DXVECTOR3 position = spotLight->getPosition();
			position.z = context->ChildValueAsFloat(index);
			spotLight->setPosition(position);
		}
		else if(strcmp(childName, "colorR") == 0)
		{
			D3DXVECTOR3 color = spotLight->getColor();
			color.x = context->ChildValueAsFloat(index);
			spotLight->setColor(color);
		}
		else if(strcmp(childName, "colorG") == 0)
		{
			D3DXVECTOR3 color = spotLight->getColor();
			color.y = context->ChildValueAsFloat(index);
			spotLight->setColor(color);
		}
		else if(strcmp(childName, "colorB") == 0)
		{
			D3DXVECTOR3 color = spotLight->getColor();
			color.z = context->ChildValueAsFloat(index);
			spotLight->setColor(color);
		}
		else if(strcmp(childName, "lookAtX") == 0)
		{
			D3DXVECTOR3 lookAt = spotLight->getLookAt();
			lookAt.x = context->ChildValueAsFloat(index);
			spotLight->setLookAt(lookAt);
		}
		else if(strcmp(childName, "lookAtY") == 0)
		{
			D3DXVECTOR3 lookAt = spotLight->getLookAt();
			lookAt.y = context->ChildValueAsFloat(index);
			spotLight->setLookAt(lookAt);
		}
		else if(strcmp(childName, "lookAtZ") == 0)
		{
			D3DXVECTOR3 lookAt = spotLight->getLookAt();
			lookAt.z = context->ChildValueAsFloat(index);
			spotLight->setLookAt(lookAt);
		}
		childName = context->ChildName(++index);
	}
	
	return spotLight;
}

GUID SpotLightComponent::getSystemIdentifier()
{
	return SCENE_SYSTEM_GUID;
}

GUID SpotLightComponent::getComponentIdentifier()
{
	return SPOT_LIGHT_COMPONENT_GUID;
}
